/**
 * SpreadSheetActivator.java
 */
package com.pluginsacceptor.plugin.spreadsheet;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;

import org.apache.log4j.Logger;

import com.pluginsacceptor.api.Activator;
import com.pluginsacceptor.api.Message;
import com.pluginsacceptor.plugin.spreadsheet.model.Cell;
import com.pluginsacceptor.plugin.spreadsheet.table.RowHeaderRenderer;
import com.pluginsacceptor.plugin.spreadsheet.table.SSTableHeaderModel;
import com.pluginsacceptor.plugin.spreadsheet.table.SSTableModel;
import com.pluginsacceptor.plugin.spreadsheet.table.SSTableModelListener;
import com.pluginsacceptor.plugin.spreadsheet.table.SSTableRenderer;
import com.pluginsacceptor.utils.CommunicationUtils;

/**
 * Spread sheet activator
 *
 * This plugin will be inject to acceptor main panel
 *
 * This plugin sends information to another plugin (addObserver() - used)
 * This plugin receives information from another plugin (getObserver() - used)
 */
public class SSActivator implements Activator {

    /** Logger */
    private static final Logger LOG = Logger.getLogger(SSActivator.class);

    /** */
    private static final int ROW_NUM = 20;

    /** */
    private static final int COLUMN_NUM = 20;

    /** */
    private SSHandler handler;

    /** */
    private JTable ssTable;

    /**
     * {@inheritDoc}
     */
    @Override
    public JComponent activate(final String[] metadata) {
        LOG.info("Activate Spread sheet plugin");
        this.handler = new SSHandler();

        final Font font = new Font("Verdana", Font.PLAIN, 10);
        final JComponent component = new JTabbedPane();
        component.setFont(font);
        component.add("Sheet0", createUiComponent());
        return component;
    }

    /**
     * Create UI component
     * @return new UI component
     */
    private JComponent createUiComponent() {

        final SSTableHeaderModel lm = new SSTableHeaderModel(ROW_NUM);
//        final DefaultTableModel dm = new DefaultTableModel(lm.getSize(), COLUMN_NUM);
        this.ssTable = new JTable(new SSTableModel(lm.getSize(), COLUMN_NUM));
        this.ssTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        final JList rowHeader = new JList(lm);
        rowHeader.setFixedCellWidth(50);
        rowHeader.setFixedCellHeight(this.ssTable.getRowHeight());
        rowHeader.setCellRenderer(new RowHeaderRenderer(this.ssTable));
//
        this.ssTable.setDefaultRenderer(Cell.class, new SSTableRenderer());
        this.ssTable.getModel().addTableModelListener(new SSTableModelListener(handler));
        this.ssTable.setCellSelectionEnabled(true);
        final ListSelectionModel cellSelectionModel = this.ssTable.getSelectionModel();
        cellSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

        this.ssTable.addMouseListener(
            new MouseListener() {
                @Override
                public void mouseReleased(final MouseEvent e) {
                    for (final int rowNum  : ssTable.getSelectedRows()) {
                      for (final int colNum : ssTable.getSelectedColumns()) {
                          handler.notifyPluginObservers(
                              CommunicationUtils.cellDataToString(
                                  rowNum, colNum, ((Cell) ssTable.getValueAt(rowNum, colNum)).getText()
                              )
                          );
                      }
                    }
                    handler.notifyPluginObservers(Message.END_SELECTION);
                }

                @Override
                public void mousePressed(final MouseEvent e) {
                    handler.notifyPluginObservers(Message.START_SELECTION);
                }

                @Override
                public void mouseExited(final MouseEvent e) {
                }

                @Override
                public void mouseEntered(final MouseEvent e) {
                }

                @Override
                public void mouseClicked(final MouseEvent e) {
                }
            }
        );

        final JScrollPane scroll = new JScrollPane(this.ssTable);
        scroll.setRowHeaderView(rowHeader);
        return scroll;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean deactivate() {
        LOG.info("Deactivate Spread sheet plugin");
        this.ssTable.removeAll();
        this.handler.deleteObservers();
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addObserver(final Observer observer) {
        LOG.info("Added observer");
        this.handler.addObserver(observer);
    }


    @Override
    public Observer getObserver() {
        return new SSObserver(this.ssTable);
    }

    public static void main(final String[] args) {
        final SSActivator activator = new SSActivator();
        final JFrame frame = new JFrame("Spread sheet debug");
        frame.setSize(800, 800);
        final JPanel panel = new JPanel();
        panel.add(new JTextField("Test"));
        panel.add(activator.activate(null));
        frame.add(panel, BorderLayout.CENTER);

        frame.pack();
        frame.setVisible(true);

        activator.addObserver(
            new Observer() {
                @Override
                public void update(final Observable arg0, final Object arg1) {
                    System.out.println(arg1);
                }
            }
        );
    }

    @Override
    public JComponent getMenuItem() {
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean load(final Object data) {
        boolean result = true;
        try {
            if (data instanceof List<?>) {
                cleanTable();
                final List<String> loadData = (List<String>) data;

                for (final String cell : loadData) {
                    if (CommunicationUtils.isCellData(cell)) {
                        ssTable.setValueAt(
                            CommunicationUtils.getValueFromCellString(cell),
                            CommunicationUtils.getRowNumFromCellString(cell),
                            CommunicationUtils.getColNumFromCellString(cell)
                        );
                    } else {
                        LOG.warn("Invalid data " + cell);
                        result = false;
                        break;
                    }
                }
            } else {
                LOG.warn("Invalid load object " + data);
                result = false;
            }
        } catch (final Exception e) {
            LOG.error("Load is failed", e);
            result = false;
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object save() {
        final List<String> data = new ArrayList<String>();
        final int rowNumSize = this.ssTable.getRowCount();
        final int colNumSize = this.ssTable.getColumnCount();
        String cellData;
        for (int rowNum = 0; rowNum < rowNumSize; rowNum++) {
            for (int colNum = 0; colNum < colNumSize; colNum++) {
                cellData = ((Cell) ssTable.getValueAt(rowNum, colNum)).getText();
                if (cellData != null && !cellData.isEmpty()) {
                    data.add(CommunicationUtils.cellDataToString(rowNum, colNum, cellData));
                }
            }
        }
        return data;
    }

    /**
     * Clearing table
     */
    public void cleanTable() {
        final int rowNumSize = this.ssTable.getRowCount();
        final int colNumSize = this.ssTable.getColumnCount();
        for (int rowNum = 0; rowNum < rowNumSize; rowNum++) {
            for (int colNum = 0; colNum < colNumSize; colNum++) {
                ssTable.setValueAt("", rowNum, colNum);
            }
        }
    }
}